package com.bestcem.xm.ticket.service.manager.record;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import com.bestcem.xm.ticket.constant.Constants;
import com.bestcem.xm.ticket.dao.TicketDao;
import com.bestcem.xm.ticket.dao.TicketRecordDao;
import com.bestcem.xm.ticket.entity.mongo.Ticket;
import com.bestcem.xm.ticket.entity.mongo.TicketRecord;
import com.bestcem.xm.ticket.entity.mongo.TicketTemplate;
import com.bestcem.xm.ticket.enums.TicketEventEnum;
import com.bestcem.xm.ticket.enums.TicketRecordSourceEnum;
import com.bestcem.xm.ticket.enums.TicketStatusEnum;
import com.bestcem.xm.ticket.enums.TicketTypeEnum;
import com.bestcem.xm.ticket.grpc.client.TicketBaseQdesGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketBaseUserGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketUserGrpcService;
import com.bestcem.xm.ticket.grpc.client.dto.qdes.QdesDTO;
import com.bestcem.xm.ticket.grpc.client.dto.user.GroupDTO;
import com.bestcem.xm.ticket.grpc.client.dto.user.GroupNodeDTO;
import com.bestcem.xm.ticket.mq.send.biz.TicketMessageSendService;
import com.bestcem.xm.ticket.service.manager.record.param.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import java.util.*;

/**
 * 工单进度记录 跟进/审核 操作工具类
 *
 * @author XiaoYunSong <ys.xiao@idiaoyan.com>
 * @version v1.0
 * @date 2021/8/18 17:22
 */
@Slf4j
@Component
public class TicketRecordManager {

    /**
     * 工单记录事件对应标题
     */
    public static final Map<TicketEventEnum, String> EVENT_TITLE_MAP = new HashMap<>();

    static {
        EVENT_TITLE_MAP.put(TicketEventEnum.SYSTEM_CREATED, "生成工单");
        EVENT_TITLE_MAP.put(TicketEventEnum.SYSTEM_CLOSED, "关闭工单");
        EVENT_TITLE_MAP.put(TicketEventEnum.MANUAL_CLOSED, "关闭工单");
        EVENT_TITLE_MAP.put(TicketEventEnum.TRANSFER_FOLLOW, "跟进转派");
        EVENT_TITLE_MAP.put(TicketEventEnum.FOLLOW_OVERDUE, "跟进逾期");
        EVENT_TITLE_MAP.put(TicketEventEnum.AUDIT_OVERDUE, "审核逾期");
        EVENT_TITLE_MAP.put(TicketEventEnum.COMMIT_FOLLOWED, "提交处理记录");
        EVENT_TITLE_MAP.put(TicketEventEnum.COMMIT_AUDITED, "审核跟进记录");
        // 2.3 新增原话创建事件
        EVENT_TITLE_MAP.put(TicketEventEnum.TRANSFER, "工单转派");
        EVENT_TITLE_MAP.put(TicketEventEnum.USER_CREATED, "创建工单");
        EVENT_TITLE_MAP.put(TicketEventEnum.REOPEN, "工单重新打开");
    }

    //    @Resource
//    private MqUtil mqUtil;
    @Resource
    private TicketDao ticketDao;
    @Resource
    private TicketRecordDao ticketRecordDao;
    @Resource
    private TicketUserGrpcService ticketUserGrpcService;
    @Resource
    private TicketBaseQdesGrpcService ticketBaseQdesGrpcService;
    @Resource
    private TicketBaseUserGrpcService ticketBaseUserGrpcService;
    @Autowired
    private TicketMessageSendService ticketMessageSendService;

    @Nullable
    private static TicketRecord getInitEntity(BaseTicketRecord record, Ticket ticket) {
        if (Objects.isNull(record) || Objects.isNull(ticket)) {
            return null;
        }
        TicketRecord entity = new TicketRecord();
        entity.setOrgId(record.getOrgId());
        entity.setTicketId(record.getTicketId());
        entity.setTitle(record.getTitle());
        entity.setSource(record.getSource());
        entity.setUserId(record.getUserId());
        entity.setUserName(record.getUserName());
        entity.setRoleId(Optional.ofNullable(record.getRoleId()).orElse(Constants.BLANK));
        entity.setRegion(Constants.BLANK);
        entity.setRegionName(record.getRegionName());
        entity.setEvent(record.getEvent().getIndex());
        entity.setCustomAttr(record.customAttr());
        entity.setSurveyId(ticket.getSurveyId());
        entity.setReason(record.getReason());
        // 2.3 TicketRecord 新增当前工单状态记录
        if (Objects.nonNull(record.getStatus())) {
            entity.setTicketStatus(record.getStatus().getIndex());
        }
        // 2.3 新增工单转派接受人
        if (record instanceof TransferTicketRecord) {
            TransferTicketRecord param = (TransferTicketRecord) record;
            entity.setReceiveUserId(param.getReceiveUserId());
            entity.setReceiveUserName(param.getReceiveUsername());
            // 转派记录里记录接收转派的 groupId
            entity.setReceiveRegionId(param.getReceiveGroupId());
            // 转派记录里记录接收转派的 groupName
            entity.setReceiveRegionName(param.getReceiveGroupName());
            entity.setReceiveRoleId(param.getReceiveRoleId());
            entity.setReceiveRoleName(param.getReceiveRoleName());

        }
        return entity;
    }

    /**
     * 工单系统处理记录
     *
     * @param event 处理事件
     * @param param 处理参数
     * @return 保存的工单记录
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/23 14:34
     */
    @Nullable
    public TicketRecord system(TicketEventEnum event, SystemTicketRecordParam param, Ticket ticket) {
        if (!EVENT_TITLE_MAP.containsKey(event)) {
            return null;
        }
        String title = EVENT_TITLE_MAP.get(event);
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 工单 {} 提交 {} 记录 ", param.getTicketId(), title);
        }

        // Ticket ticket = ticketDao.findById(param.getTicketId());
        if (Objects.isNull(ticket)) {
            log.error("[Ticket] 工单系统处理记录 ticket 不存在; Id: {}", param.getTicketId());
            return null;
        }
        TicketRecord entity = new TicketRecord();
        entity.setOrgId(param.getOrgId());
        entity.setTicketId(param.getTicketId());
        entity.setTitle(title);
        if (TicketEventEnum.TRANSFER_FOLLOW.equals(event) || TicketEventEnum.TRANSFER.equals(event)) {
            Object followerInfo = param.getFollowerInfo();
            if (Objects.nonNull(followerInfo)) {
                entity.setTitle(title + "至" + followerInfo.toString());
            }
        }
        entity.setEvent(event.getIndex());
        entity.setSource(TicketRecordSourceEnum.SYSTEM.getIndex());
        // jy.zhao 2.3需求，新增手动创建
        if (TicketEventEnum.MANUAL_CLOSED.equals(event)
                || TicketEventEnum.REOPEN.equals(event) || TicketEventEnum.TRANSFER.equals(event)) {
            entity.setSource(TicketRecordSourceEnum.MANUAL.getIndex());
            // 工单关闭原因
            entity.setReason(param.getReason());
        }
        // 工单状态保存，2.3新增
        entity.setTicketStatus(param.getStatus().getIndex());
        entity.setRegionName(param.getRegionName());
        String userName = ObjectUtils.isEmpty(param.getUserName()) ? "系统" : param.getUserName();
        entity.setUserName(userName);
        entity.setSurveyId(ticket.getSurveyId());
        entity = ticketRecordDao.saveTicketRecord(entity);

        boolean forbiddenPublish = param.isForbiddenPublish();
        if (forbiddenPublish) {
            return entity;
        }

        TicketStatusEnum status = param.getStatus();
        TicketTypeEnum tType = param.getType();
        if (TicketTypeEnum.UN_NEED_DEAL.equals(tType)) {
            status = TicketStatusEnum.UNNEED_DEAL;
        }

        TicketStatusEnum ticketStatus = TicketStatusEnum.getByIndex(ticket.getStatus());
        if (Objects.isNull(ticketStatus)) {
            log.error("[Ticket] 工单系统处理记录 ticket status 异常; Id: {}; Status: {}", param.getTicketId(), ticket.getStatus());
            return entity;
        }
        if (Objects.isNull(status)) {
            status = ticketStatus;
        } /*else {
            if (ticketStatus.equals(status)) {
                return entity;
            }

            if (TicketStatusEnum.MANUAL_CLOSED.equals(status)
                    || TicketStatusEnum.SYSTEM_CLOSED.equals(status)
                    || TicketStatusEnum.CLOSED.equals(status)) {

                if (TicketStatusEnum.MANUAL_CLOSED.equals(ticketStatus)
                        || TicketStatusEnum.SYSTEM_CLOSED.equals(ticketStatus)
                        || TicketStatusEnum.CLOSED.equals(ticketStatus)) {
                    return entity;
                }
            }
        }*/
        if (TicketStatusEnum.CREATED.equals(status)) {
            status = TicketStatusEnum.FOLLOWING;
        }

        /*if (Objects.nonNull(ticket.getOperationType()) && TicketOperationTypeEnum.MANUAL.getIndex().equals(ticket.getOperationType())) {
            // 手动新建工单暂时不需要发送该消息，因为手动创建工单时没有问卷信息的
            return entity;
        }*/

        // 发送MQ
        sendTicketRecordCreatedMq(ticket, entity, status, title);
        return entity;
    }

    /**
     * 提交工单跟进记录
     *
     * @param param          工单跟进参数
     * @param ticketTemplate 工单对应规则对应模板
     * @return 提交后的工单跟进记录
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/19 16:18
     */
    @Nullable
    public FollowedTicketRecord followed(FollowedTicketRecordParam param, TicketTemplate ticketTemplate) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 工单 {} 提交跟进记录; Param: {}; Template: {}", param.getTicketId(), param, ticketTemplate);
        }

        param.setTitle(EVENT_TITLE_MAP.get(TicketEventEnum.COMMIT_FOLLOWED));
        param.setSource(TicketRecordSourceEnum.MANUAL.getIndex());
        FollowedTicketRecord followedTicketRecord = FollowedTicketRecord.getInstance(param, ticketTemplate);

        if (Objects.isNull(followedTicketRecord)) {
            log.error("[Ticket] 构建工单进度记录 跟进 信息工具类失败; Param: {}", param);
            return null;
        }
        TicketRecord ticketRecord = save(followedTicketRecord);
        if (Objects.isNull(ticketRecord)) {
            log.error("[Ticket] 保存工单跟进记录保存失败; Util: {}", followedTicketRecord);
            return followedTicketRecord;
        }
        followedTicketRecord.setId(ticketRecord.getId());
        return followedTicketRecord;
    }

    /**
     * 提交工单审核记录
     *
     * @param param 工单审核参数
     * @return 提交后的工单跟进记录
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/19 16:24
     */
    @Nullable
    public AuditedTicketRecord audited(AuditedTicketRecordParam param) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 工单 {} 提交审核记录; Param: {}", param.getTicketId(), param);
        }

        param.setTitle(EVENT_TITLE_MAP.get(TicketEventEnum.COMMIT_AUDITED));
        param.setSource(TicketRecordSourceEnum.MANUAL.getIndex());
        AuditedTicketRecord auditedTicketRecord = AuditedTicketRecord.getInstance(param);
        if (Objects.isNull(auditedTicketRecord)) {
            log.error("[Ticket] 构建工单进度记录 审核 信息工具类失败; Param: {}", param);
            return null;
        }
        TicketRecord ticketRecord = save(auditedTicketRecord);
        if (Objects.isNull(ticketRecord)) {
            log.error("[Ticket] 保存工单审核记录保存失败; Util: {}", auditedTicketRecord);
            return auditedTicketRecord;
        }
        auditedTicketRecord.setId(ticketRecord.getId());
        return auditedTicketRecord;
    }

    /**
     * 提交工单转派记录
     *
     * @param param 工单转派参数
     * @return 提交后的工单转派记录
     * @author liheng
     * @date 2021/9/8 18:07
     */
    @Nullable
    public TransferTicketRecord transfer(TransferTicketRecordParam param) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 工单 {} 提交转派记录; Param: {}", param.getTicketId(), param);
        }
        TicketEventEnum event = param.getEvent();
        if (!EVENT_TITLE_MAP.containsKey(event)) {
            return null;
        }
        String title = EVENT_TITLE_MAP.get(event);
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 工单 {} 提交 {} 记录 ", param.getTicketId(), title);
        }

        Ticket ticket = ticketDao.findById(param.getTicketId());
        if (Objects.isNull(ticket)) {
            log.error("[Ticket] 工单系统处理记录 ticket 不存在; Id: {}", param.getTicketId());
            return null;
        }
        param.setTitle(title);
        param.setSource(TicketRecordSourceEnum.MANUAL.getIndex());
        // 设置工单状态为 跟进中
        param.setStatus(TicketStatusEnum.FOLLOWING);

        TransferTicketRecord transferTicketRecord = TransferTicketRecord.getInstance(param);
        if (Objects.isNull(transferTicketRecord)) {
            log.error("[Ticket] 构建工单进度记录 审核 信息工具类失败; Param: {}", param);
            return null;
        }
        TicketRecord ticketRecord = save(transferTicketRecord);
        if (Objects.isNull(ticketRecord)) {
            log.error("[Ticket] 保存工单审核记录保存失败; Util: {}", transferTicketRecord);
            return transferTicketRecord;
        }
        transferTicketRecord.setId(ticketRecord.getId());
        return transferTicketRecord;
    }

    /**
     * 提交工单重新打开记录
     *
     * @param param 工单重新打开参数
     * @return 提交后的工单重新打开记录
     * @author liheng
     * @date 2021/9/8 18:07
     */
    @Nullable
    public ReopenTicketRecord reopenRecord(ReopenTicketRecordParam param) {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 工单 {} 提交重新打开记录; Param: {}", param.getTicketId(), param);
        }

        param.setTitle(EVENT_TITLE_MAP.get(TicketEventEnum.REOPEN));
        param.setSource(TicketRecordSourceEnum.MANUAL.getIndex());
        // 设置工单状态为 跟进中
        param.setStatus(TicketStatusEnum.FOLLOWING);

        ReopenTicketRecord reopenTicketRecord = ReopenTicketRecord.getInstance(param);
        if (Objects.isNull(reopenTicketRecord)) {
            log.error("[Ticket] 构建工单进度记录 审核 信息工具类失败; Param: {}", param);
            return null;
        }
        TicketRecord ticketRecord = save(reopenTicketRecord);
        if (Objects.isNull(ticketRecord)) {
            log.error("[Ticket] 保存工单审核记录保存失败; Util: {}", reopenTicketRecord);
            return reopenTicketRecord;
        }
        reopenTicketRecord.setId(ticketRecord.getId());
        return reopenTicketRecord;
    }

    /**
     * 工单 跟进/审核/转派/重新打开 记录保存
     *
     * @param self 工单 跟进/审核/转派/重新打开 进度记录信息
     * @return 保存的记录信息
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/18 19:25
     */
    @Nullable
    private TicketRecord save(BaseTicketRecord self) {
        if (Objects.isNull(self)) {
            log.error("[Ticket] 工单记录保存 入参为空");
            return null;
        }
        Ticket ticket = ticketDao.findById(self.getTicketId());
        if (Objects.isNull(ticket)) {
            log.error("[Ticket] 工单记录保存 工单为空; Self: {}", self);
            return null;
        }
        TicketRecord entity = getInitEntity(self, ticket);
        if (Objects.isNull(entity)) {
            log.error("[Ticket] 工单记录保存 初始化 TicketRecord 失败; Self: {}; Ticket: {}", self, ticket);
            return null;
        }
        entity = ticketRecordDao.saveTicketRecord(entity);

        TicketStatusEnum status = TicketStatusEnum.getByIndex(ticket.getStatus());
        if (Objects.isNull(status)) {
            log.error("[Ticket] 工单记录保存 工单状态异常; Ticket: {}", ticket);
            return entity;
        }
        if (Objects.nonNull(self.getStatus())) {
            TicketStatusEnum selfStatus = self.getStatus();
            if (status.equals(selfStatus)) {
                return entity;
            }

            if (TicketStatusEnum.MANUAL_CLOSED.equals(selfStatus)
                    || TicketStatusEnum.SYSTEM_CLOSED.equals(selfStatus)
                    || TicketStatusEnum.CLOSED.equals(selfStatus)) {
                if (TicketStatusEnum.MANUAL_CLOSED.equals(status)
                        || TicketStatusEnum.SYSTEM_CLOSED.equals(status)
                        || TicketStatusEnum.CLOSED.equals(status)) {
                    return entity;
                }
            }
            status = selfStatus;
        }
        if (TicketStatusEnum.CREATED.equals(status)) {
            status = TicketStatusEnum.FOLLOWING;
        }

        // 发送MQ
        sendTicketRecordCreatedMq(ticket, entity, status, entity.getTitle());

        return entity;
    }

    /**
     * 获取 user.group.code
     *
     * @param region groupId
     * @return code
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/19 17:42
     */
    @Nonnull
    private String getCode(String region) {
        if (!ObjectUtils.isEmpty(region)) {
            GroupDTO group = ticketBaseUserGrpcService.getGroup(region);
            return Optional.ofNullable(group).map(GroupDTO::getCode).orElse(Constants.BLANK);
        }
        return "";
    }

    /**
     * 获取 survey.surveyNo
     *
     * @param surveyId 问卷id
     * @return surveyNo
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/19 17:43
     */
    @Nonnull
    private String getSurveyNo(String surveyId) {
        if (!ObjectUtils.isEmpty(surveyId)) {
            QdesDTO qdesDTO = ticketBaseQdesGrpcService.getQdesProject(surveyId);
            return Optional.ofNullable(qdesDTO).map(QdesDTO::getCode).orElse(Constants.BLANK);
        }
        return "";
    }

    // ================== private static method ==================

    /**
     * 发送 ticket_record_created MQ及相关前置处理
     *
     * @param ticket       工单信息
     * @param ticketRecord 工单记录信息
     * @param status       工单状态
     * @param title        title
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/19 17:35
     */
    public void sendTicketRecordCreatedMq(Ticket ticket, TicketRecord ticketRecord, TicketStatusEnum status, String title) {
        Map<String, Object> mqData = getMqDto(ticket, ticketRecord, status, title);
        if (!ObjectUtils.isEmpty(ticket.getRegion())) {
            List<GroupNodeDTO> groupNodeDTOList = ticketUserGrpcService.listAncestorGroupsByGroupId(ticket.getRegion());
            if (!CollectionUtils.isEmpty(groupNodeDTOList)) {
                for (GroupNodeDTO node : groupNodeDTOList) {
                    mqData.put(node.getId(), Optional.ofNullable(node.getTitle()).orElse(Constants.BLANK));
                }
            }
        }
        // 发送工单创建MQ
//        mqUtil.sendAppMq(MqUtil.TICKET_RECORD_CREATED, mqData);
        ticketMessageSendService.ticketRecordCreatedSend(mqData);
    }

    /**
     * 获取 MQ 发送的数据
     *
     * @param ticket       工单信息
     * @param ticketRecord 工单记录信息
     * @param status       工单状态
     * @param title        title
     * @return MQ发送DTO
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2021/8/19 17:49
     */
    @Nonnull
    private Map<String, Object> getMqDto(@Nonnull Ticket ticket, @Nonnull TicketRecord ticketRecord,
                                         @Nonnull TicketStatusEnum status, String title) {
        String code = getCode(ticket.getRegion());
        String surveyNo = getSurveyNo(ticket.getSurveyId());
        String userId = Optional.ofNullable(ticketRecord.getUserId()).orElse(Constants.BLANK);

        Map<String, Object> mqData = new HashMap<>();
        String ticketCreateTimeStr = DateUtil.format(ticket.getCreatedDate(), DatePattern.NORM_DATETIME_MS_PATTERN);
        mqData.put("ticket_created_dt", Validator.isNotEmpty(ticketCreateTimeStr) ? ticketCreateTimeStr : "");
        mqData.put("surveyId", ticket.getSurveyId());
        mqData.put("ticketNo", ticket.getTicketNo());
        mqData.put("status", status.getIndex());
        mqData.put("region", ticket.getRegion());
        mqData.put("code", code);
        mqData.put("regionName", ticket.getRegionName());
        mqData.put("surveyTitle", ticket.getSurveyTitle());
        mqData.put("surveyNo", surveyNo);
        mqData.put("resId", ticket.getResId());
        mqData.put("ticketId", ticket.getId());
        mqData.put("event", ticketRecord.getEvent());
        mqData.put("title", title);
        mqData.put("userId", userId);
        mqData.put("userName", ticketRecord.getUserName());
        mqData.put("source", ticketRecord.getSource());
        mqData.put("roleId", ticketRecord.getRoleId());
        mqData.put("id", ticketRecord.getId());
        String ticketRecordCreateTimeStr = DateUtil.format(ticketRecord.getCreatedDate(), DatePattern.NORM_DATETIME_MS_PATTERN);
        mqData.put("created_dt", Validator.isNotEmpty(ticketRecordCreateTimeStr) ? ticketRecordCreateTimeStr : "");

        return mqData;
    }
}
